//****************************************************************************/
//  (c) Copyright 2010 IPcore.cn. All rights reserved.
//  Vendor              : IPcore.cn                          
//  Version             : Initial                           
//  Application         : FRUC                          
//  Filename            : dram_access.v                  
//  Date Last Modified  : $Date: 2010/08/02 12:17:54 $  
//  Date Created        : Mon Aug 2 2010                
//  Author              : Eric Yan  
//  Email               : Eric0208@Gmail.com    
//  Description         : 
//
//****************************************************************************/

module dram_access(
    fruc_clk            ,
    fruc_rstj           ,
    
    c1_calib_done       ,
    
    test_st_addr        ,//start addr
    
    test_cmd_en         ,  
    test_cmd_instr      ,  
    test_cmd_bl         ,  
    test_cmd_byte_addr  ,  
    test_cmd_empty      ,  
    test_cmd_full       ,  
    test_wr_en          ,  
    test_wr_mask        ,
    test_wr_data        ,
    test_wr_full        ,  
    test_wr_empty       ,  
    test_wr_count       ,  
    test_wr_underrun    ,  
    test_wr_error       ,  
    test_rd_en          ,  
    test_rd_data        ,
    test_rd_full        ,
    test_rd_empty       ,  
    test_rd_count       ,  
    test_rd_overflow    ,  
    test_rd_error     
    );
    
        
input           fruc_clk            ;
input           fruc_rstj           ;
input           c1_calib_done       ;  

input  [29:0]   test_st_addr        ;
                
output          test_cmd_en         ;
output [2:0]    test_cmd_instr      ;
output [5:0]    test_cmd_bl         ;
output [29:0]   test_cmd_byte_addr  ;
input           test_cmd_empty      ;
input           test_cmd_full       ;

output          test_wr_en          ;
output [7:0]    test_wr_mask        ;//7:0
output [63:0]   test_wr_data        ;//63:0
input           test_wr_full        ;
input           test_wr_empty       ;
input  [6:0]    test_wr_count       ;
input           test_wr_underrun    ;
input           test_wr_error       ;

output          test_rd_en          ;
input  [63:0]   test_rd_data        ;//63:0
input           test_rd_full        ;
input           test_rd_empty       ;
input  [6:0]    test_rd_count       ;
input           test_rd_overflow    ;
input           test_rd_error       ;

parameter       UDLY                = 1;

wire            memc_error          = test_cmd_en & test_cmd_full|
                                      test_wr_underrun|test_wr_error|
                                      test_rd_overflow|test_rd_error;

wire            mem_init            = !c1_calib_done;
wire            mem_wrdy            = !test_wr_full;
wire            mem_rrdy            = !test_rd_empty;


parameter       TEST_IDLE = 5'b0000_1;
parameter       TEST_WDAT = 5'b0001_0;
parameter       TEST_WCMD = 5'b0010_0;
parameter       TEST_RCMD = 5'b0100_0;
parameter       TEST_RDAT = 5'b1000_0;

reg  [04:00]    test_cs;
reg  [04:00]    test_ns;
wire            idle2wdat;
wire            wdat2wcmd;
wire            wcmd2rcmd;
wire            rcmd2rdat;
wire            rdat2idle;
wire            rdat2wdat;

always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        test_cs <= #UDLY TEST_IDLE;
    else
        test_cs <= #UDLY test_ns;

always @(*)
begin
    case(test_cs)
        TEST_IDLE: begin
            if(idle2wdat) 
                test_ns = #200000 TEST_WDAT;
            else
                test_ns = test_cs;
        end
        TEST_WDAT: begin
            if(wdat2wcmd) 
                test_ns = TEST_WCMD;
            else
                test_ns = test_cs;
        end
        TEST_WCMD: begin
            if(wcmd2rcmd) 
                test_ns = TEST_RCMD;
            else
                test_ns = test_cs;
        end
        TEST_RCMD: begin
            if(rcmd2rdat) 
                test_ns = TEST_RDAT;
            else
                test_ns = test_cs;
        end
        TEST_RDAT: begin
            if(rdat2idle) 
                test_ns = TEST_IDLE;
            else if(rdat2wdat)
                test_ns = TEST_WDAT;
            else
                test_ns = test_cs;
        end
        default:test_ns = TEST_IDLE;
    endcase
end

wire    idle_st = test_cs[0];
wire    wdat_st = test_cs[1];
wire    wcmd_st = test_cs[2];
wire    rcmd_st = test_cs[3];
wire    rdat_st = test_cs[4];


////////idle
assign  idle2wdat = c1_calib_done;

wire [5:0]    test_cmd_bl         = 6'h3f;

////////wdata phase
reg     [05:00] wr_cnt;
assign          wdat2wcmd = (wr_cnt==test_cmd_bl);
reg     [63:00] test_wr_data ;//= {8{2'b00,wr_cnt[05:00]}};
wire            test_wr_en   = wdat_st;
wire    [07:00] test_wr_mask = 8'h0;

always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        wr_cnt <= #UDLY 'h0;
    else if(wcmd_st)
        wr_cnt <= #UDLY 'h0;
    else if(wdat_st)
        wr_cnt <= #UDLY wr_cnt + 'b1;
        
///////write/read cmd
wire          test_cmd_en         = wcmd_st|rcmd_st;
wire [2:0]    test_cmd_instr      = {2'b00,rcmd_st};
reg  [29:0]   test_cmd_byte_addr  ;//= 30'h0;
    
assign          wcmd2rcmd           = test_cmd_en;
assign          rcmd2rdat           = test_cmd_en;

always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        test_wr_data <= #UDLY 'h0;
    else if(test_wr_en)
        test_wr_data <= #UDLY test_wr_data + 'b1;

always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        test_cmd_byte_addr <= #UDLY test_st_addr;
    else if(rcmd_st)
        test_cmd_byte_addr <= #UDLY test_cmd_byte_addr + 'h100;//64*64b
////////rdata phase
reg     [14:00] loop_cnt;
reg     [05:00] rd_cnt;
wire            test_rd_en   = rdat_st & !test_rd_empty;
assign          rdat2idle = (rd_cnt==test_cmd_bl) & test_rd_en & (&loop_cnt);
assign          rdat2wdat = (rd_cnt==test_cmd_bl) & test_rd_en;

always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        rd_cnt <= #UDLY 'h0;
    else if(rcmd_st)
        rd_cnt <= #UDLY 'h0;
    else if(test_rd_en)
        rd_cnt <= #UDLY rd_cnt + 'b1;
        
always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        loop_cnt <= #UDLY 'h0;
    else if(rdat_st & rdat2wdat)
        loop_cnt <= #UDLY loop_cnt + 'b1;
        
//////////simulation finish
always @(posedge fruc_clk)
    if(rdat_st & rdat2wdat)
        $display("Dram Access Test Loop %d",loop_cnt);
    else if(rdat_st & rdat2idle)
        #1000000 $finish;

reg [63:00] rdata_cnt;
always @(posedge fruc_clk or negedge fruc_rstj)
    if(!fruc_rstj)
        rdata_cnt <= #UDLY 'h0;
    else if(test_rd_en)
        rdata_cnt <= #UDLY rdata_cnt + 'b1;

always @(posedge fruc_clk)
    if((rdata_cnt != test_rd_data)&test_rd_en)
        $display("Read Data Failed @ %h",rdata_cnt);
        
endmodule
